using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using QQZiFramework;
using QQZiFramework.Membership;
using QQZiFramework.Modals;
using System.DrawingCore;
using Microsoft.Extensions.Hosting;

namespace QQZiFramework.Mvc
{
    public class QQZiApiController : ControllerBase, IQQZiController
    {

        bool? _IsApplicationJson;
        public bool IsApplicationJson
        {
            get
            {
                if (_IsApplicationJson != null) return _IsApplicationJson.Value;
                if (Request.ContentType != null && Request.ContentType.IndexOf(appJson, StringComparison.OrdinalIgnoreCase) > -1)
                {
                    _IsApplicationJson = true;
                }
                else _IsApplicationJson = false;
                return _IsApplicationJson.Value;
            }
        }


        const string appJson = "application/json";

        /// <summary>
        /// 获取参数值，并转换为指定类型
        /// </summary>
        /// <param name="name">参数名</param>
        /// <param name="throwNull">为空是否异常</param>
        /// <param name="ifNull">如果参数为空，是否设置默认值</param>
        /// <returns></returns>
        [NonAction]
        public T GetParamValue<T>(string name, bool throwNull = false, object ifNull = null) where T : IConvertible
        {
            string s = GetParamValue(name, throwNull);
            if (string.IsNullOrEmpty(s))
            {
                if (ifNull != null) return (T)Convert.ChangeType(ifNull, typeof(T));
                return default(T);
            }
            return (T)Convert.ChangeType(s, typeof(T));
        }

        /// <summary>
        /// 获取参数值
        /// </summary>
        /// <param name="name">参数名称</param>
        /// <param name="maxLength">最大长度，超过则报异常</param>
        /// <param name="throwNull">如果参数为空是否报异常</param>
        /// <returns></returns>
        [NonAction]
        public string GetParamValue(string name, int maxLength, bool throwNull = false)
        {
            return GetParamValue(name, maxLength, true, throwNull);
        }

        /// <summary>
        /// 获取参数值
        /// </summary>
        /// <param name="name">参数名称</param>
        /// <param name="maxLength">最大长度，超过则报异常</param>
        /// <param name="throwNull">如果参数为空是否报异常</param>
        /// <returns></returns>
        [NonAction]
        public string GetParamValue(string name, int maxLength, bool decode, bool throwNull)
        {

            string str = Request.Query[name];
            if (str == null)
            {
                if (Request.Method != "POST")
                {
                    if (throwNull) throw new ClientException("参数" + name + "值不能为空!");
                    else return null;

                }
                if (Request.ContentLength == null || Request.ContentLength.Value == 0) str = null;
                else
                {
                    if (IsApplicationJson)
                        str = WebHostMemberShip.GetPostJsonParamVal(this, name);
                    else
                        str = Request.Form[name];
                }
            }
            if (string.IsNullOrEmpty(str) || str == "undefined")
            {
                if (throwNull) throw new ClientException("参数" + name + "值不能为空!");
                else return null;
            }
            str = str.Replace('\'', ' ').Trim(); //过滤单引号
            if (str.Length > 5)
            {
                if (decode) str = System.Net.WebUtility.UrlDecode(str);
                Utility.RemoeScriptTag(ref str);
                Utility.CheckSqlXSS(str);
            }
            if (maxLength > 0 && str.Length > maxLength) throw new ClientException("参数" + name + "长度超过" + maxLength + "!");
            return str;
        }

        /// <summary>
        /// 客户端传json上来，解析为实体对象(url编码+base64编码)
        /// </summary>
        /// <typeparam name="T">实休类型</typeparam>
        /// <param name="name">参数名</param>
        /// <param name="throwNull"></param>
        /// <returns></returns>
        [NonAction]
        public T GetJsonParam<T>(string name, bool throwNull = false)
        {
            string str = Request.Form[name];
            if (str == null) str = Request.Query[name];
            if (throwNull && string.IsNullOrEmpty(str)) throw new ClientException("参数" + name + "值不能为空!");
            if (str != null)
            {
                str = Utility.DecodeBase64(str);
                str = System.Web.HttpUtility.UrlDecode(str);
                return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(str);
            }
            else return default(T);
        }

        /// <summary>
        /// 获取参数值，如果超过255长度会异常
        /// </summary>
        /// <param name="name">参数名称</param>
        /// <param name="throwNull">如果参数为空是否报异常</param>
        /// <returns></returns>
        [NonAction]
        public string GetParamValue(string name, bool throwNull = false)
        {
            return GetParamValue(name, 255, throwNull);
        }

        /// <summary>
        /// 登录后记录cookie以及相关日志
        /// Redis中会记录token(login_userid)及对应的userid
        /// </summary>
        protected TokenInfo RecordThirdAppLogin(string appId, BaseUser userInfo, string terminal, DBContext context)
        {
            WebHostMemberShip memberShip = (WebHostMemberShip)context.Membership;
            DateTime expires = DateTime.Today.AddMonths(1);
            TokenInfo tokenInfo = memberShip.SetUserLoginState(userInfo, LoginUserStateType.Redis, expires, LoginPlatfromId.Admin, appId, context);
            int device = -1; // GetParamValue<int>("device", false, -1);//设备 
            string cityId = null; // GetParamValue("cityId", false);//城市code
            string location = null; // GetParamValue("location", false);
            int isAdmin = 0;
            userInfo.AppTermId = terminal;
            if (device == -1)
            {
                //if (GetWeiXinUser() != null) device = 2;
                if (WebHostMemberShip.IsAjax(context)) device = 3;
                else if (context.IsMobileDevice) device = 1;
                else device = 0;
            }
            context.SaveUserRecord(userInfo, cityId, location, device, 0, isAdmin, terminal, Request.Headers["User-Agent"], WebHostMemberShip.GetWebClientIp(Request));
            context.LogMessage("用户" + userInfo.Name + "(" + userInfo.Account + "，" + userInfo.UserId + ") 登录，Token:" + tokenInfo.Token, "登录");
            return tokenInfo;
        }

        /// <summary>
        /// 登录后记录cookie以及相关日志
        /// Redis中会记录token(login_userid)及对应的userid
        /// </summary>
        protected TokenInfo RecordLogin(BaseUser userInfo, LoginUserStateType userStateType, LoginPlatfromId platform, DBContext context)
        {
            return RecordLogin(userInfo, userStateType, platform, null, context);
        }
        protected TokenInfo RecordLogin(BaseUser userInfo, LoginUserStateType userStateType, LoginPlatfromId platform, object extValues, DBContext context)
        {
            TokenInfo tokenInfo = SetUserLoginState(userInfo, userStateType, platform, extValues, context);

            int device = GetParamValue<int>("device", false, -1); //设备 
            string terminal = GetParamValue("terminal", false); //终端号
            string cityId = GetParamValue("cityId", false); //城市code 
            string location = GetParamValue("location", false);
            string PushId = GetParamValue("PushId", false);
            int isAdmin = 0;
            if (platform == LoginPlatfromId.Admin) isAdmin = 1;

            userInfo.AppTermId = terminal;
            if (!string.IsNullOrEmpty(PushId)) userInfo.PushId = PushId;
            string userAgent = Request.Headers["User-Agent"];
            if (device == -1)
            {
                //if (GetWeiXinUser() != null) device = 2;
                if (userAgent.IndexOf("Weex/") > 0) device = 3;
                else if (context.IsMobileDevice) device = 1;
                else device = 0;
            }
            context.SaveUserRecord(userInfo, cityId, location, device, 0, isAdmin, terminal, userAgent, WebHostMemberShip.GetWebClientIp(Request));
            context.LogMessage("用户" + userInfo.Name + "(" + userInfo.Account + "，" + userInfo.UserId + ") 登录，Token:" + tokenInfo.Token, "登录");
            return tokenInfo;
        }

        /// <summary>
        /// 登录后记录cookie以及相关日志
        /// <param name="platform">登录后台</param>
        /// </summary>
        protected TokenInfo RecordLogin<U>(U userInfo, LoginPlatfromId platform, DBContext context) where U : BaseUser
        {
            if (GetParamValue<int>("useToken") == 1)
                return RecordLogin(userInfo, LoginUserStateType.Redis, platform, context);
            else
                return RecordLogin(userInfo, context.Membership.UserStateType, platform, context);
        }

        /// <summary>
        /// 注销登录
        /// <param name="isAdmin">1是运营平台登录</param>
        /// </summary>
        [LoginCheckFilter(IsCheck = false)]
        protected void RecordLogoff(int isAdmin, DBContext context)
        {
            if (context.IsLogin())
            {
                context.LogMessage(context.LoginUser.Name + "退出登录");
                string UserAgent = Request.Headers["User-Agent"];
                int device = GetParamValue<int>("device", false, -1); //设备
                if (device == -1)
                {
                    //if (GetWeiXinUser() != null) device = 2;
                    if (UserAgent.IndexOf("Weex/") > 0) device = 3;
                    else if (context.IsMobileDevice) device = 1;
                    else device = 0;
                }
                string terminal = GetParamValue("terminal", false); //终端号

                context.GetBusiness<MembershipBLL>().SaveUserRecord(context.LoginUser.UserId, device, 1, isAdmin, terminal, UserAgent, WebHostMemberShip.GetWebClientIp(Request), null, null);
                context.LoginUser.PushId = IDBEntity.DbNullString;
                context.Update(context.LoginUser, "PushId");
                context.DeleteRedisItem("User_" + context.LoginUser.UserId);
                string token = ((WebHostMemberShip)context.Membership).GetRequestToken(context);
                if (token != null)
                {
                    context.DeleteRedisItem("login_" + token);
                }
                else
                {
                    throw new NotImplementedException();
                    // if (Request.Cookies["userCity"] != null) {
                    //     Request.Cookies["userCity"].Expires = DateTime.Today;
                    //     Response.Cookies.Add (Request.Cookies["userCity"]);
                    // }
                    // Request.Cookies["userinfo"].Expires = DateTime.Today;
                    // Response.Cookies.Add (Request.Cookies["userinfo"]);
                }
            }
            //清除微信以外的session
            // for (int i = 0; i < HttpContext.Session.Count; i++)
            // {
            //     if ("weixin" != HttpContext.Session.Keys[i]) HttpContext.Session.Remove(HttpContext.Session.Keys[i]);
            // }
        }


        /// <summary>
        /// 保存用户信息到cookie或者session
        /// </summary>
        /// <param name="userInfo">用户信息</param>
        /// <param name="Expires">超时时间</param>
        /// <returns>TokenInfo,0:返回Token供客户端（比如app），1：appSecret</returns>
        protected TokenInfo SetUserLoginState(BaseUser userInfo, LoginUserStateType userStateType, LoginPlatfromId platfromId, object extVallues, DBContext context)
        {
            string tokenExpires = context.GetSettingValue<string>("Basic:TokenExpires");
            if (tokenExpires == null) tokenExpires = "1m";
            if (extVallues == null && platfromId != LoginPlatfromId.Admin && platfromId != LoginPlatfromId.App)
            {
                tokenExpires = "1d";//如果是商家登录等，还没开通后台账户的，设为一天超时
            }
            DateTime expires;
            char lastChar = tokenExpires[tokenExpires.Length - 1];
            if (lastChar == 'm' || lastChar == 'M')
            {
                //超时时间以月为单位
                expires = DateTime.Today.AddMonths(Convert.ToInt32(tokenExpires.Substring(0, tokenExpires.Length - 1)));
            }
            else
            {
                tokenExpires = tokenExpires.Replace("d", "").Replace("D", "");
                expires = DateTime.Today.AddDays(Convert.ToInt32(tokenExpires));
            }
            return context.Membership.SetUserLoginState(userInfo, userStateType, expires, platfromId, extVallues, context);
        }
        protected bool isCreateNew = false;

        protected bool IsMobileDevice()
        {
            return CreateDBContext().IsMobileDevice;
        }

        protected bool IsDevelopment()
        {
            return QQZiFramework.Mvc.Extension.Hosting.IsDevelopment();
        }

        private string DomainName;
        protected string DomainServer
        {
            get
            {
                if (DomainName == null)
                {
                    DomainName = CreateDBContext().GetSettingValue<string>("DomainName");
                    if (DomainName != null && DomainName[DomainName.Length - 1] != '/') DomainName += "/";
                }
                return DomainName;
            }
        }
        [NonAction]
        public string GetEditEntity()
        {
            DBContext context = CreateDBContext();
            object strObj = context.GetArgument("dosave-entityJson");
            if (strObj == null)
            {
                string entityJson;
                if (Request.ContentLength == null || Request.ContentLength.Value == 0) entityJson = null;
                else
                {
                    if (IsApplicationJson)
                        entityJson = WebHostMemberShip.GetPostJsonParamVal(this, "entityJson");
                    else
                        entityJson = Request.Form["entityJson"];
                }
                if (entityJson == null) throw new Exception("entityJson is null");
                entityJson = Utility.DecodeBase64(entityJson);
                entityJson = System.Web.HttpUtility.UrlDecode(entityJson);
                string scripts = Utility.RemoeScriptTag(ref entityJson);
                if (!string.IsNullOrEmpty(scripts)) throw new ClientException("检测到有非法的数据提交！");
                context.SetArgument("dosave-entityJson", entityJson);
                return entityJson;
            }
            else
            {
                return strObj.ToString();
            }


        }

        /// <summary>
        /// 是否以传token方式访问（比如App）
        /// </summary>
        /// <returns></returns>
        protected bool IsTokenMode()
        {
            return GetRequestToken() != null;
        }
        protected string GetRequestToken()
        {
            return ((WebHostMemberShip)CreateDBContext().Membership).GetRequestToken(CreateDBContext());
        }

        /// <summary>
        /// 获取Webconfig中appsetting的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns> 
        protected T GetAppSetting<T>(string name, char end, bool throwNull = true)
        {
            DBContext context = CreateDBContext();
            T t = context.GetSettingValue<T>(name, throwNull);
            if (t is string)
            {
                string str = t.ToString();
                if (end != ' ')
                {
                    if (str[str.Length - 1] != end) str = str + end;
                }
                t = (T)Convert.ChangeType(str, typeof(T));
            }
            return t;
        }

        protected string GetAppSetting(string name, bool isUrl = false)
        {
            return GetAppSetting<string>(name, isUrl ? '/' : ' ');
        }

        /// <summary>
        /// 实体类全名，可重载，空则为全局配置
        /// </summary>
        protected virtual string EntityFormat { get { return null; } }
        public struct PaggerResult { public int sEcho; public int iTotalRecords; public int iTotalDisplayRecords; public string[][] aaData; }

        /// <summary>
        /// 组织DBContext的格式化来源（用来替换配置中的{loginUserId}等）
        /// </summary>
        protected virtual System.Collections.Hashtable GetDBContextFormatSource()
        {
            if (m_formatSourcehashTable != null) return m_formatSourcehashTable;
            m_formatSourcehashTable = new System.Collections.Hashtable();
            BaseUser u = CreateDBContext().LoginUser;
            if (u != null)
            {
                m_formatSourcehashTable.Add("loginUserId", u.UserId);
            }
            else
            {
                m_formatSourcehashTable.Add("loginUserId", "0");
            }

            return m_formatSourcehashTable;
        }
        System.Collections.Hashtable m_formatSourcehashTable;

        /// <summary>
        /// 导出到Excel
        /// </summary>
        /// <param name="fieldMap">导出字段集合，json格式，{fieldName1:中文名1,fieldName2:中文名2}</param>
        [LoginCheckFilter(IsCheck = false)]
        [HttpPost]
        [HttpGet]
        public virtual ActionResult ToExcel(string fieldMap, string fileName)
        {
            string permission = GetParamValue<string>("permission");
            string entityName = GetQueryEntityName();
            string whereField = GetParamValue<string>("whereField");
            string orderBy = GetParamValue<string>("orderBy");
            DataTable dt;
            using (DBContext db = CreateDBContext())
            {
                if (db.HasLock("ExportExcel-" + permission)) throw new Exception("当前导出操作频繁，请稍候！");
                TokenInfo tokenInfo = ((WebHostMemberShip)db.Membership).GetTokenInfo(db);
                if (!db.GetBusiness<MembershipBLL>().HasPermisson(tokenInfo.UserId, permission, tokenInfo.PlatfromId)) throw new NotAlowAccessException();
                db.FormatDataSource = GetDBContextFormatSource();
                whereField = System.Web.HttpUtility.UrlDecode(whereField);
                if (string.IsNullOrEmpty(fileName)) fileName = entityName;
                if (string.IsNullOrEmpty(fieldMap)) throw new ClientException("没有定义要导出的列fieldMap");
                fieldMap = System.Web.HttpUtility.UrlDecode(fieldMap);
                Dictionary<string, string> whereDic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(whereField);
                string queryField = "";
                Dictionary<string, string> chinessNames = JsonConvert.DeserializeObject<Dictionary<string, string>>(fieldMap);
                if (chinessNames.Count == 0) throw new ClientException("没有要导出的列");
                foreach (KeyValuePair<string, string> kv in chinessNames)
                {
                    queryField += "," + kv.Key;
                }
                queryField = queryField.Substring(1);
                QueryParam param = new QueryParam() { StrictModel = true, permission = permission, queryField = queryField, entityName = db.GetFullName(entityName), orderBy = orderBy };
                foreach(var ki in whereDic){
                    param.AddWhere(ki.Key,ki.Value);
                }
                OnQuerying(param, db);
                dt = db.DoQuery(param);
                db.Close();
                return DataTableToExcel(dt, chinessNames, fileName);
            }

        }
        /// <summary>
        /// 导出到Excel
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="chinessNames">导出字段集合，json格式，{fieldName1:中文名1,fieldName2:中文名2}</param>
        protected FileResult DataTableToExcel(DataTable dt, Dictionary<string, string> chinessNames, string fileName)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<table cellpadding='0' cellspacing='0' border=0 style='border: solid 1px #000;border-collapse: collapse; '><tr>");
            foreach (DataColumn col in dt.Columns)
            {
                string chiness;
                if (chinessNames == null) chiness = col.ColumnName;
                else
                {
                    chinessNames.TryGetValue(col.ColumnName, out chiness);
                    if (chiness == null) chiness = col.ColumnName;
                }
                sb.Append("<td style='border: solid 1px #000; '>" + chiness + "</td>");
            }
            sb.Append("</tr>");
            foreach (DataRow dr in dt.Rows)
            {
                sb.Append("<tr>");
                foreach (DataColumn col in dt.Columns)
                {
                    if (dr[col].ToString().Length >= 15)
                    {
                        sb.Append("<td style='border: solid 1px #000; '>'" + dr[col].ToString() + "</td>");
                    }
                    else
                    {
                        sb.Append("<td style='border: solid 1px #000; '>" + dr[col].ToString() + "</td>");
                    }

                }
                sb.Append("</tr>");
            }
            sb.Append("</table>");
            return File(System.Text.Encoding.UTF8.GetBytes(sb.ToString()), "application/vnd.ms-excel", fileName + ".xls");
        }

        DBContext _dbcontext;


        /// <summary>
        /// 创建DBContext，如果一个过程已经创建则直接返回实例
        /// </summary>
        /// <returns></returns>
        [NonAction]
        public virtual DBContext CreateDBContext()
        {
            if (_dbcontext == null)
            {
                _dbcontext = new DBContext();
                ((WebHostMemberShip)_dbcontext.Membership).SetContextArgs(_dbcontext, HttpContext);
                _dbcontext.FormatDataSource = GetDBContextFormatSource();
            }
            return _dbcontext;
        }

        protected virtual string GetQueryEntityName()
        {
            return GetParamValue<string>("entityName");
        }
        /// <summary>
        /// 执行列表查询操作，返回json字符串，如果请求中包含pageIndex，将会进行分页查询
        /// 树型查询需要传tree和parent参数
        /// </summary>
        /// <param name="permission">查询权限配置</param>
        /// <param name="queryField">查询的字符，以逗号隔开</param>
        /// <param name="entityName">查询的对象实体类名（不需要完整名,Name即可）</param>
        /// <param name="whereField">条件表达式json</param>
        /// <param name="orderBy">排序</param>
        /// <returns></returns>
        [LoginCheckFilter(IsCheck = true, CheckPermission = "FromRequest")]
        [HttpGet]
        [HttpPost]
        public virtual string DoQuery(string permission, string entityName, string queryField, string whereField, string orderBy, int pageIndex, int pageSize, string groupByFields)
        {
            if (string.IsNullOrEmpty(permission)) permission = GetParamValue<string>("permission");
            if (string.IsNullOrEmpty(queryField)) queryField = GetParamValue<string>("queryField");
            if (string.IsNullOrEmpty(entityName)) entityName = GetQueryEntityName();
            if (string.IsNullOrEmpty(whereField)) whereField = GetParamValue<string>("whereField");
            if (string.IsNullOrEmpty(orderBy)) orderBy = GetParamValue<string>("orderBy");
            if (permission == null) throw new ArgumentNullException("permission");
            if (entityName == null) throw new ArgumentNullException("entityName");
            if (queryField == null) throw new ArgumentNullException("queryField");
            bool isTree = GetParamValue("tree") == "1";
            // permission = System.Net.WebUtility.UrlDecode(permission);
            // queryField = System.Net.WebUtility.UrlDecode(queryField);

            // orderBy = System.Net.WebUtility.UrlDecode(orderBy);
            // entityName = System.Net.WebUtility.UrlDecode(entityName);
            if (entityName == "ConfigParam") entityName = "QQZiFramework.DataBase.ConfigParam,QQZiFramework";
            QJsonMessage jr = new QJsonMessage();
            using (DBContext db = CreateDBContext())
            {

                if (db.FormatDataSource == null) db.FormatDataSource = GetDBContextFormatSource();
                Dictionary<string, string> whereDic;
                if (string.IsNullOrEmpty(whereField)) whereDic = new Dictionary<string, string>();
                else
                {
                    whereField = System.Net.WebUtility.UrlDecode(whereField);
                    if (whereField != null && whereField.IndexOf(" or ", StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        throw new Exception("存在入侵嫌疑！");
                    }
                    whereDic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(whereField);
                }
                QueryParam param = new QueryParam() { StrictModel = true, permission = permission, queryField = queryField, entityName = db.GetFullName(entityName),orderBy = orderBy };
                foreach(var ki in whereDic){
                    param.AddWhere(ki.Key,ki.Value);
                }
                OnQuerying(param, db);
                if (param.entityType == typeof(LogEvent)) db.LogSql = SqlLogMode.NoLog; //日志查询不记录
                if (isTree)
                {
                    param.TreeParent = GetParamValue("parent");
                    jr.Result = db.QueryTree(param, param.TreeParent);
                }
                else
                {
                    //int pageIndex = GetParamValue<int>("pageIndex", false, -1);
                    if (pageIndex > 0)
                    {
                        if (pageSize < 1) pageSize = 20;
                        //int pagesize = GetParamValue<int>("pagesize", false, 25);
                        param.Page = new Pagger() { PageIndex = pageIndex, PageSize = pageSize };
                        if (groupByFields == null) groupByFields = GetParamValue<string>("GroupByFields", false);
                        if (!string.IsNullOrEmpty(groupByFields))
                        {
                            param.Page.SetGroupByFields(groupByFields);
                        }
                        jr.Result = db.DoQuery(param);
                        jr.Total = param.Page.Total;
                        jr.GroupBy = param.Page.GroupByDic;
                    }
                    else jr.Result = db.DoQuery(param);
                    OnQueryed(param, jr, db);
                }
                db.Close();
            }
            return jr.ToJson(false, false);
        }

        /// <summary>
        /// 在查询列表请求执行前
        /// </summary>
        /// <param name="param"></param>
        protected virtual void OnQuerying(QueryParam param, DBContext db) { }

        protected virtual void OnQueryed(QueryParam param, QJsonMessage qm, DBContext db) { }

        //private void SetTreeChildren(DBContext context, IDBEntity entity, QQZiFramework.DataBase.CustomerProperty cp)
        //{
        //    QQZiFramework.DataBase.CustomerProperty primaryCodeCP = context.GetPropertyByDBName(cp.Attr.ForeignTableField);
        //   object primaryCode=  primaryCodeCP.Info.GetValue(entity, null);
        //    ITreeDBEntity treeEntity = entity as ITreeDBEntity;
        //    if (treeEntity == null) throw new ClientException(context.GetInstance().Param.entityType.Name + "不是ITreeDBEntity类型，或者查询数据转换为空");
        //    context.GetInstance().Param.ClientWhere[cp.GetDBFieldName()] = primaryCode.ToString();
        //    treeEntity.Children = context.DoQueryEntity(context.GetInstance().Param);
        //    foreach (IDBEntity sub in treeEntity.Children)
        //    {   
        //        SetTreeChildren(context, sub, cp);
        //    }
        //}

        /// <summary>
        /// 查询单个对象
        /// </summary>
        /// <param name="permission">查询权限配置</param>
        /// <param name="entityName">查询的对象实体类名（不需要完整名,Name即可）</param>
        /// <param name="primaryVal">主键的值</param>
        /// <returns></returns>
        [LoginCheckFilter(IsCheck = true, CheckPermission = "FromRequest")]
        [HttpGet]
        [HttpPost]
        public virtual string DoGetOne(string permission, string entityName, string queryField, string primaryVal)
        {
            if (string.IsNullOrEmpty(permission)) permission = GetParamValue<string>("permission");
            if (string.IsNullOrEmpty(queryField)) queryField = GetParamValue<string>("queryField");
            if (string.IsNullOrEmpty(entityName)) entityName = GetQueryEntityName();
            if (string.IsNullOrEmpty(primaryVal)) primaryVal = GetParamValue<string>("primaryVal");


            if (permission == null) throw new ArgumentNullException("permission");
            if (entityName == null) throw new ArgumentNullException("entityName");
            if (queryField == null) throw new ArgumentNullException("queryField");

            if (entityName == "ConfigParam") entityName = "QQZiFramework.DataBase.ConfigParam,QQZiFramework";
            JsonMessage jr = new JsonMessage();
            using (DBContext db = CreateDBContext())
            {

                if (db.FormatDataSource == null) db.FormatDataSource = GetDBContextFormatSource();
                DataTable dt;
                QueryParam param;
                if (!string.IsNullOrEmpty(primaryVal))
                {
                    param = new QueryParam() { entityName = db.GetFullName(entityName), permission = permission, queryField = queryField };
                    param.AddWhere(param.LoaderInfo.PrimaryCusPro.Info.Name, primaryVal);
                }
                else
                {
                    string whereField = GetParamValue<string>("whereField", true);
                    if (whereField != null && whereField.IndexOf(" or ", StringComparison.OrdinalIgnoreCase) > -1)
                    {
                        throw new Exception("存在入侵嫌疑！");
                    }
                    Dictionary<string, string> whereDic = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, string>>(whereField);
                    param = new QueryParam() { permission = permission, queryField = queryField, entityName = db.GetFullName(entityName) };
                    foreach(var ki in whereDic){
                    param.AddWhere(ki.Key,ki.Value);
                }
                }
                param.StrictModel = true;
                OnQuerying(param, db);
                dt = db.DoQuery(param);
                if (dt.Rows.Count > 0) OnGetOneSuccess(permission, dt.Rows[0]);
                jr.Result = ParseSingleDataTable(dt);
                db.Close();
            }
            return jr.ToJson();

        }
        /// <summary>
        /// 查询单个对象成功后
        /// </summary>
        /// <param name="entity"></param>
        protected virtual void OnGetOneSuccess(string permission, DataRow entity) { }

        private Dictionary<string, object> ParseSingleDataTable(DataTable dt)
        {
            if (dt.Rows.Count > 0)
            {
                //转字典，为了序列化成单个实体
                Dictionary<string, object> jsonDic = new Dictionary<string, object>();
                foreach (DataColumn dc in dt.Columns)
                {
                    jsonDic.Add(dc.ColumnName, dt.Rows[0][dc]);
                }
                return jsonDic;
            }
            return null;
        }

        /// <summary>
        /// 保存对象，参数有permission,entityName,entityJson
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [LoginCheckFilter(IsCheck = true, CheckPermission = "FromRequest")]
        public virtual string DoSave()
        {
            string permission = GetParamValue("permission");
            string entityName = GetQueryEntityName();
            if (entityName == "ConfigParam") entityName = "QQZiFramework.DataBase.ConfigParam,QQZiFramework";

            string queryField = GetParamValue("queryField", 500);
            JsonMessage jr = new JsonMessage();
            using (DBContext db = CreateDBContext())
            {
                string entityJson = GetEditEntity();
                IDBEntity entity = db.DeserializeEntity(permission, entityName, entityJson);
                //QueryParam param = new QueryParam() { entityName = GetFullName(entityName), permission = permission }
                if (db.FormatDataSource == null) db.FormatDataSource = GetDBContextFormatSource();
                EntityLoaderInfo loaderInfo = EntityLoaderInfo.GetEntityLoaderInfo(entity.GetType());
                isCreateNew = entity.ValueIsNull(loaderInfo.PrimaryCusPro.Info);
                db.BeginTransaction();
                IDBEntity oldEntity = null;
                string columns = "";
                if (!isCreateNew)
                {
                    //更新，查出原来的值 ，对比变化情况
                    object obj = entity.GetPrimaryValue();
                    QueryParam param = db.ConvertPrimaryQueryParam(permission, entity.GetType(), obj.ToString());
                    param.queryField = queryField;
                    oldEntity = db.DoGetOne(param, "");
                    //Newtonsoft.Json.Linq.JToken jsonToken = Newtonsoft.Json.Linq.JToken.Parse(entityJson);
                    foreach (CustomerProperty customerProperty in loaderInfo.CustomerPropertys)
                    {
                        if(customerProperty.IsPrimaryKey()) continue;
                        if (customerProperty.Attr != null && customerProperty.Attr.Usage == DBFieldUsage.NoField) continue;
                        if (!customerProperty.Info.CanWrite) continue;                        
                        object oldValue = customerProperty.Info.GetValue(oldEntity, null);
                        object newValue = customerProperty.Info.GetValue(entity, null);
                        if (newValue != null && !newValue.Equals(oldValue))
                        {
                            //有变更
                            columns += "," + customerProperty.Info.Name;
                        }
                        else
                        {
                            if (!customerProperty.Info.GetType().IsValueType)
                            {
                                //如果是引用类型，则直接赋空
                                customerProperty.Info.SetValue(entity, null);
                            }
                        }
                    }
                }
                if (onDBContextSaving(jr, permission, entityName, entity, oldEntity, db) == true)
                {
                    if (GetParamValue("tree") == "1")
                    {
                        //获取parent属性的定义
                        QQZiFramework.CustomerProperty cp = loaderInfo.GetParentCustomerProperty();
                        object parentVal = cp.Info.GetValue(entity, null);
                        if (parentVal == null || entity.ValueIsNull(cp.Info))
                        {
                            //如果实体本身没给parent赋值,则从参数中取
                            string s = GetParamValue("parent", true);
                            parentVal = Convert.ChangeType(s, cp.Info.PropertyType);
                            if (parentVal == null) parentVal = "0";
                            cp.Info.SetValue(entity, parentVal, null);
                        }
                        //获取parent属性对应的字段ForeignTableField定义(parent外键对应的主键字段)
                        CustomerProperty primaryCodeCP = loaderInfo.GetPropertyByDBName(cp.Attr.ForeignProperty);
                        if (primaryCodeCP == null) throw new ClientException("Parent外键没定义或者没有对应的主键!");
                        if (isCreateNew)
                        {
                            if (!primaryCodeCP.IsPrimaryKey())
                            {
                                DBTableAttribute tableAttr = db.GetTableAttr(entity.GetType());
                                int codeLength = tableAttr.TreeCodeLenth;
                                if (codeLength == 0) codeLength = 2;
                                //如果parent的值不是对应主键记录，则对code重新编号
                                //获取parent下最大的code
                                string sql = "select max(" + primaryCodeCP.GetDBFieldName(entity) + ") from " + tableAttr.TableName + " where " + cp.GetDBFieldName(entity) + "='" + parentVal + "' ";
                                if (loaderInfo.MarkDeleteCusPro != null) sql += " and " + loaderInfo.MarkDeleteCusPro.GetDBFieldName(entity) + " <> -1";
                                object scalar = db.ExecScalar(sql);
                                if (scalar == DBNull.Value)
                                {
                                    if (parentVal.Equals(0) || parentVal.Equals("0")) scalar = "A".PadLeft(codeLength, 'A');
                                    else scalar = parentVal + "A".PadLeft(codeLength, 'A');
                                }
                                else
                                {
                                    string maxValStr = scalar.ToString();
                                    string str = Utility.Code26Add(maxValStr, 1);
                                    if (str.Length < codeLength) str = str.PadLeft(codeLength, 'A');
                                    else if (str.Length > maxValStr.Length) throw new ClientException("超过允许的子结点的最大数量");
                                    scalar = str;
                                }
                                primaryCodeCP.Info.SetValue(entity, scalar, null);
                            }
                        }
                        else
                        {
                            if (parentVal is int) parentVal = IDBEntity.DefaultNullValue;
                            else parentVal = null;
                            cp.Info.SetValue(entity, parentVal, null); //不更新Parent列
                        }
                        db.DoSave(entity, permission, null, true);
                    }
                    else
                    {
                        if (isCreateNew)
                        {
                            db.DoSave(entity, permission, null, true);
                        }
                        else
                        {


                            if (columns.Length > 1)
                            {
                                db.Update(entity, columns.Substring(1));
                            }
                        }
                    }
                    onDBContextSaved(jr, permission, entityName, entity, db);
                }
                else
                {
                    object obj = entity.GetPrimaryValue();
                    if (obj == null || obj.Equals(0) || obj.Equals(IDBEntity.DefaultNullValue)) throw new ClientException("自定义Saving后需要给entity主键赋值");
                }
                jr.Result = GetOne(db, permission, entityName, entity.GetPrimaryValue().ToString(), queryField);
                db.Close();
            }
            return JsonConvert.SerializeObject(jr);
        }

        /// <summary>
        /// 获取单条查询的内容，主要用于保存后查询
        /// </summary>
        /// <returns></returns>
        protected Dictionary<string, object> GetOne(DBContext context, string permission, string entityName, string primaryVal, string queryField)
        {
            QueryParam param = context.ConvertPrimaryQueryParam(permission, entityName, primaryVal, queryField);
            OnQuerying(param, context);
            DataTable dt = context.DoQuery(param);
            if (dt.Rows.Count > 0)
            {
                //转字典，为了序列化成单个实体
                Dictionary<string, object> jsonDic = new Dictionary<string, object>();
                foreach (DataColumn dc in dt.Columns)
                {
                    jsonDic.Add(dc.ColumnName, dt.Rows[0][dc]);
                }
                return jsonDic;
            }
            else
            {
                throw new NotAlowAccessException(); //有可能更新的是自己没权限访问的(permission有配置Defaults的情况)
            }
        }

        protected virtual bool onDBContextSaving(JsonMessage jr, string permission, string entityName, IDBEntity entity, IDBEntity oldEntity, DBContext context)
        {
            return true;
        }

        /// <summary>
        /// 触发之后的事件
        /// </summary>
        /// <param name="jr"></param>
        /// <param name="permission"></param>
        /// <param name="entityName"></param>
        /// <param name="entity"></param>
        /// <param name="context"></param>
        protected virtual void onDBContextSaved(JsonMessage jr, string permission, string entityName, IDBEntity entity, DBContext context)
        {

        }
        protected virtual void onDBContextDeleting(ref string permission, string primaryValue, DBContext context) { }
        protected virtual void onDBContextDeleted(string permission, IDBEntity entity, DBContext context) { }
        /// <summary>
        /// 删除对象，如果有标记删除则为update，参数有permission,entityName,primaryID
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [LoginCheckFilter(IsCheck = true, CheckPermission = "FromRequest")]
        public virtual string DoDelete()
        {
            string permission = GetParamValue<string>("permission");
            string entityName = GetQueryEntityName();
            string primaryID = GetParamValue<string>("primaryID");
            if (entityName == "ConfigParam") entityName = "QQZiFramework.DataBase.ConfigParam,QQZiFramework";
            JsonMessage jr = new JsonMessage();
            using (DBContext db = CreateDBContext())
            {
                if (db.FormatDataSource == null) db.FormatDataSource = GetDBContextFormatSource();
                onDBContextDeleting(ref permission, primaryID, db);
                IDBEntity entity = db.DoGetOne(permission, entityName, primaryID, null, "", false);
                jr.Result = db.DoDelete(permission, entityName, primaryID);
                onDBContextDeleted(permission, entity, db);
                db.Close();
            }
            return JsonConvert.SerializeObject(jr);
        }

        // /// <summary>
        // /// 获取登录用户的ID
        // /// </summary>
        // /// <returns></returns>
        // protected int GetUserID()
        // {
        //     return GetUser().UserId;
        // }

        // private BaseUser m_loginUser;
        // /// <summary>
        // /// 当前登录用户，不能在DBContext还没初始化完成的时候调
        // /// </summary>
        // /// <returns></returns> 
        // [NonAction]
        // public virtual BaseUser GetUser(bool throwNull = true)
        // {
        //     if (m_loginUser == null && )
        //     {
        //         m_loginUser = CreateDBContext().LoginUser;
        //         if (m_loginUser == null) { if (throwNull) throw new NotLoginException(); } else if (m_loginUser.Status < 0 && m_loginUser.Status > -10) throw new ClientException("您已被限制登录！");
        //     }
        //     return m_loginUser;
        // }


        // /// <summary>
        // /// 记录区域代码和地区
        // /// </summary>
        // /// <param name="address"></param>
        // /// <param name="code"></param>
        // public void RecordCity (string address, string code) {
        //     if (string.IsNullOrEmpty (address)) return;
        //     if (string.IsNullOrEmpty (code)) return;
        //     HttpCookie cookie = new HttpCookie ("userCity");
        //     cookie.Values["City"] = Utility.Encrypt (address);
        //     cookie.Values["CityId"] = Utility.Encrypt (code);
        //     cookie.Expires = DateTime.MaxValue; // DateTime.Now.AddHours(1);
        //     Response.Cookies.Add (cookie);
        // }

        // /// <summary>
        // /// 切换区域城市
        // /// </summary>
        // /// <param name="id"></param>
        // public void ChangeCity (string id, string address) {
        //     RecordCity (address, id);
        // }

        //public string GetUserLastLoginTime()
        //{
        //    if (Request.Cookies["userinfo"] == null) throw new NotLoginException();
        //    if (string.IsNullOrEmpty(Request.Cookies["userinfo"]["LastLoginTime"])) return null;
        //    return Utility.Decrypt(Request.Cookies["userinfo"]["LastLoginTime"]);
        //}

        // /// <summary>
        // /// 微信分享 获取 signature签名
        // /// <para>要带杠</para>
        // /// </summary> 
        // protected Hashtable GetWeiXinShare(string url)
        // {

        //     DBContext context = CreateDBContext();
        //     WeixinDriver wx = context.GetBusiness<WeixinDriver>();
        //     string js = wxApiAccessTokenDriver.GetJsapiTicket();
        //     string timestamp = Common.GetNowTime();
        //     string noncestr = Common.GenerateNonceStr();
        //     Hashtable hashtable = new Hashtable();
        //     string Signature = wx.GetSignature(noncestr, timestamp, url).ToLower();
        //     hashtable.Add("appid", wxApiAccessTokenDriver.Setting.appId);
        //     hashtable.Add("timestamp", timestamp);
        //     hashtable.Add("noncestr", noncestr);
        //     hashtable.Add("signature", Signature);
        //     hashtable.Add("url", url);
        //     CreateDBContext().LogMessage(string.Format("url:{0},ticket:{1},noncestr:{2},timestamp:{3},signature:{4}", url, js, noncestr, timestamp, Signature), "微信签名");
        //     return hashtable;
        // }

        // WxAccessTokenDriver _driver;
        // protected WxAccessTokenDriver wxApiAccessTokenDriver
        // {
        //     get
        //     {
        //         if (_driver == null) _driver = WxAccessTokenDriver.Create(CreateDBContext(), WxAccessWhich.MPAPI);
        //         return _driver;
        //     }
        // }

        // /// <summary>
        // /// 客户端backUrl跳转判断
        // /// </summary>
        // /// <param name="page"></param>
        // /// <returns></returns>
        // public string GetClientRedirect (string page) {
        //     if (HttpContext.Session["backurl"] != null) {
        //         page = HttpContext.Session["backurl"].ToString ();
        //         HttpContext.Session["backurl"] = null;
        //     }
        //     return page;
        // }

        // /// <summary>
        // /// 重新载入DBContext配置
        // /// </summary>
        // public virtual string ReloadConfig()
        // {
        //     DBContext.ReloadConfig();
        //     return "success";
        // }

        /// <summary>
        /// 图片下载，转传到图片服务器
        /// </summary>
        /// <returns></returns>
        protected JsonMessage ServerDownloadImage(string imgUrl)
        {
            using (DBContext context = CreateDBContext())
            {
                string server_bg = GetAppSetting<string>("ImageServer:UploadBG", '/', false);
                string server_out = GetAppSetting<string>("0", '/', false);
                if (server_out == null) server_out = GetAppSetting<string>("ImageServer", '/', false);
                if (server_bg == null) server_bg = server_out;
                else if (server_out == null) server_out = server_bg;
                //oem是否有重载
                server_bg = context.GetSettingValue<string>("ImageServer:UploadBG", false, server_bg);
                server_out = context.GetSettingValue<string>("ImageServer:AccessOut", false, server_out);
                if (string.IsNullOrEmpty(server_bg) || server_bg == "." || server_bg == "./" || server_bg.StartsWith(Request.Host.Value))
                {
                    //本机是图片服务器
                    string shortTime = DateTime.Now.ToString("yyyy/MM/dd") + "/";
                    string filePhysicalPath = QQZiFramework.Mvc.Extension.MapPath("~/Content/Upload/" + shortTime);
                    string fileName = Guid.NewGuid().ToString() + ".jpg";
                    CreateDBContext().NewHttpUtility().Download(imgUrl, filePhysicalPath + "/" + fileName, null);
                    string server = (string.IsNullOrEmpty(server_out) ? DomainServer : server_out);
                    JsonMessage jsonMessage = new JsonMessage();
                    jsonMessage.Result = server + "Content/Upload/" + shortTime + "/" + fileName;
                    return jsonMessage;
                }
                else
                {
                    string actionUrl = server_bg + context.OEM.Name + "/Home/DownloadImage";
                    string json = context.NewHttpUtility().DoPost(actionUrl, "url=" + System.Web.HttpUtility.UrlEncode(imgUrl));
                    JsonMessage jm = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonMessage>(json);
                    return jm;
                }
            }
        }

        protected JsonMessage SaveImageToServer(Bitmap b)
        {
            DBContext context = CreateDBContext();
            string server_bg = GetAppSetting<string>("ImageServer:UploadBG", '/', false);
            string server_out = GetAppSetting<string>("0", '/', false);
            if (server_out == null) server_out = GetAppSetting<string>("ImageServer", '/', false);
            if (server_bg == null) server_bg = server_out;
            else if (server_out == null) server_out = server_bg;
            //oem是否有重载
            server_bg = context.GetSettingValue<string>("ImageServer:UploadBG", false, server_bg);
            server_out = context.GetSettingValue<string>("ImageServer:AccessOut", false, server_out);
            if (string.IsNullOrEmpty(server_bg) || server_bg == "." || server_bg == "./" || server_bg.StartsWith(Request.Host.Value))
            {
                //本机是图片服务器
                string fileName = Guid.NewGuid().ToString() + ".jpg";
                string shortFilePath = DateTime.Now.ToString("yyyy/MM/dd");
                string filePhysicalPath = QQZiFramework.Mvc.Extension.MapPath("~/Content/Upload/" + shortFilePath);
                if (!System.IO.Directory.Exists(filePhysicalPath))
                {
                    System.IO.Directory.CreateDirectory(filePhysicalPath);
                }
                shortFilePath = shortFilePath + "/" + fileName;
                filePhysicalPath = System.IO.Path.Combine(filePhysicalPath, fileName);
                context.LogMessage("保存合并后的图片:" + filePhysicalPath);
                b.Save(filePhysicalPath, System.DrawingCore.Imaging.ImageFormat.Jpeg);
                string server = (string.IsNullOrEmpty(server_out) ? DomainServer : server_out);
                JsonMessage jsonMessage = new JsonMessage();
                jsonMessage.Result = server + "Content/Upload/" + shortFilePath;
                return jsonMessage;
            }
            else
            {
                MyHttpUtility http = CreateDBContext().NewHttpUtility();
                MemoryStream ms = new MemoryStream();
                b.Save(ms, System.DrawingCore.Imaging.ImageFormat.Jpeg);
                byte[] bytes = ms.ToArray();
                ms.Close();
                string actionUrl = server_bg + context.OEM.Name + "/Home/UploadImage?istemp=1";
                string backStr = http.Upload(actionUrl, bytes, null);
                JsonMessage jm = JsonConvert.DeserializeObject<JsonMessage>(backStr);
                return jm;
            }
        }

    }

}